﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using LumenWorks.Framework.IO.Csv;
using VDS.RDF.Writing.Contexts;

namespace GeoNames2RDF
{
   class Program
   {
      //Индексы полей в CSV-дампе

      private const int countryInfoIsoIndex = 0;
      private const int countryInfoCountryIndex = 4;
      private const int countryInfoPopulationIndex = 7;
      private const int countryInfoGeoNameIdIndex = 16;

      private const int citiesGeoNameIdIndex = 0;
      private const int citiesNameIndex = 1;
      private const int citiesLatitudeIndex = 4;
      private const int citiesLongitudeIndex = 5;
      private const int citiesFeatureClassIndex = 6;
      private const int citiesCountryCodeIndex = 8;
      private const int citiesPopulationIndex = 14;
      private const int citiesTimeZoneIndex = 17;

      private const int alternateNamesGeoNameIdIndex = 1;
      private const int alternateNamesIsoLanguageIndex = 2;
      private const int alternateNamesAlternateNameIndex = 3;
      private const int alternateNamesIsPreferredIndex = 4;

      // маппинг названия культуры на GeoNameId страны
      private static Dictionary<string, string> isoToCountryGeoNameIdDictionary = new Dictionary<string, string>();
      // импортированные GeoNameId
      private static Dictionary<string, object> usedGeoNameIdsDictionary = new Dictionary<string, object>(); // is used for alternative names

      static void Main(string[] args)
      {
         // RDF-массив для поиска (с названиями и альтернативными именами)
         StreamWriter streamWriter = new StreamWriter("GeoNames.n3", false);
         // RDF-массив для логического вывода (
         StreamWriter streamWriter4Filtering = new StreamWriter("GeoNames4Filtering.n3", false);

         #region CountryInfo

         Console.WriteLine("Start process countries");

         using (GeoNamesReader csv = new GeoNamesReader(new StreamReader("countryInfo.txt", Encoding.UTF8)))
         {
            while (csv.ReadNextRecord())
            {
               string geoNameId = csv[countryInfoGeoNameIdIndex];

               string iso = csv[countryInfoIsoIndex];

               string countryName = csv[countryInfoCountryIndex];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, "name", countryName));

               string population = csv[countryInfoPopulationIndex];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, "population", Int32.Parse(population)));

               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, "isCountry", "true"));

               isoToCountryGeoNameIdDictionary.Add(iso, geoNameId);
               usedGeoNameIdsDictionary.Add(geoNameId, null);
            }
         }

         Console.WriteLine("Finish process countries");

         #endregion CountryInfo

         #region Cities

         Console.WriteLine("Start process cities");

         StreamWriter absentIsoStreamWriter = new StreamWriter("AbsentIso.txt", false, Encoding.UTF8);
         int absentIsoCount = 0;

         using (GeoNamesReader csv = new GeoNamesReader(new StreamReader("cities5000.txt", Encoding.UTF8)))
         {
            while (csv.ReadNextRecord())
            {
               string geoNameId = csv[citiesGeoNameIdIndex];

               string cityName = csv[citiesNameIndex];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, "name", cityName));

               string latitude = csv[citiesLatitudeIndex];
               streamWriter.WriteLine(TriplesHelper.GetWgs84TripleString(geoNameId, "lat", Decimal.Parse(latitude)));

               string longitude = csv[citiesLongitudeIndex];
               streamWriter.WriteLine(TriplesHelper.GetWgs84TripleString(geoNameId, "long", Decimal.Parse(longitude)));

               string featureClass = csv[citiesFeatureClassIndex];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId,
                  "featureClass",
                  new Uri(NamesHelper.GetGeoNamesOntologyUri(featureClass))));

               string countryCode = csv[citiesCountryCodeIndex];
               if (!isoToCountryGeoNameIdDictionary.ContainsKey(countryCode))
               {
                  absentIsoCount++;
                  absentIsoStreamWriter.WriteLine(countryCode);
                  continue;
               }
               string countryGeoNameId = isoToCountryGeoNameIdDictionary[countryCode];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, 
                  "inCountry", 
                  new Uri(NamesHelper.GetGeoNamesEntityUri(countryGeoNameId))));

               streamWriter4Filtering.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId,
                  "inCountry",
                  new Uri(NamesHelper.GetGeoNamesEntityUri(countryGeoNameId))));

               string population = csv[citiesPopulationIndex];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, "population", Int32.Parse(population)));

               string timeZone = csv[citiesTimeZoneIndex];
               streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, "timezone", timeZone));

               usedGeoNameIdsDictionary.Add(geoNameId, null);
            }
         }

         absentIsoStreamWriter.Close();

         Console.WriteLine("Finish process cities");

         #endregion Cities

         #region AlternateNames

         Console.WriteLine("Start process alternate names");

         using (GeoNamesReader csv = new GeoNamesReader(new StreamReader("alternateNames.txt", Encoding.UTF8)))
         {
            while (csv.ReadNextRecord())
            {
               string geoNameId = csv[alternateNamesGeoNameIdIndex];

               if (usedGeoNameIdsDictionary.ContainsKey(geoNameId))
               {
                  string iso = csv[alternateNamesIsoLanguageIndex];
                  
                  string alternateName = csv[alternateNamesAlternateNameIndex];

                  string isPreferred = csv[alternateNamesIsPreferredIndex];

                  if (String.IsNullOrEmpty(iso))
                     streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, 
                        isPreferred == "1" ? "preferredName" : "alternateName", 
                        alternateName));
                  else
                  {
                     string predicateName = null;
                     if (iso.Length == 2)
                        predicateName = isPreferred == "1" ? "preferredName" : "alternateName";
                     else if (iso == "link")
                     {
                        Match match = Regex.Match(alternateName, @"^http://(\w{2}).wikipedia.org");
                        if (!match.Success)
                           continue;
                        iso = match.Groups[1].Value;
                        predicateName = "wikipediaArticle";
                     }
                     else
                        continue;

                     streamWriter.WriteLine(TriplesHelper.GetGeoNamesTripleString(geoNameId, 
                        predicateName, 
                        alternateName, iso));
                  }
               }
            }
         }

         Console.WriteLine("Finish process alternate names");

         #endregion AlternateNames

         streamWriter.Close();
         streamWriter4Filtering.Close();
      }
   }
}
